package layers.physical;

import java.util.ArrayList;

public class Path {

	private ArrayList<Crossroad> totalPath;
	private long distanceLeft;
	public int index = 0;

	public Path() {
		this(new ArrayList<Crossroad>());
	}

	@SuppressWarnings("unchecked")
	public Path(ArrayList<Crossroad> path) {
		super();
		this.totalPath = (ArrayList<Crossroad>) path.clone();
		this.distanceLeft = this.updateDistanceLeft();
	}

	private Path(ArrayList<Crossroad> path, int i, long d) {
		this(path);
		this.index = i;
		this.distanceLeft = d;
	}

	private long updateDistanceLeft() {
		long result = 0;
		for(int i = index; i < this.totalPath.size() - 1; i++){
			Road road = totalPath.get(i).getConnectionTo(totalPath.get(i+1));
			result += road.getLength();
		}
		return result;
	}

	public Crossroad getCurrent(){
		return this.totalPath.get(index);
	}


	public void addCrossroadToPath(Crossroad cr){
		if(cr == null)
			throw new IllegalArgumentException("Crossroad must not be null");
		if(!totalPath.get(totalPath.size()-1).isConnected(cr))
			throw new IllegalArgumentException("Crossroad must be reachable from the last crossroad in the path");
		if(this.totalPath.contains(cr))
			System.out.println("Loop!");
		this.totalPath.add(cr);
	}

	protected void setTotalPath(ArrayList<Crossroad> path) {
		this.totalPath = path;
	}

	public Path reset(){
		this.index = 0;
		return this;
	}

	public Path getClone(){
		return new Path(totalPath,index,distanceLeft);
	}

	public boolean hasNext() {
		return index < totalPath.size()-1;
	}

	public long getTotalDistance(){
		long result = 0;
		for(int i = 0; i < this.totalPath.size() - 1; i++){
			Road road = totalPath.get(i).getConnectionTo(totalPath.get(i+1));
			result += road.getLength();
		}
		return result;
	}

	public boolean pathInList(ArrayList<Path> rejectedPaths) {
		boolean matchFound = false;
		for(Path r : rejectedPaths){
			if(r.getTotalDistance() == this.getTotalDistance() && r.totalPath.size() == this.totalPath.size()){
				matchFound = true;
				for(int i=0;i<r.totalPath.size();i++){
					if(!r.totalPath.get(i).equals(this.totalPath.get(i))){
						matchFound = false;
						break;
					}
				}
			}
		}
		return matchFound;
	}

	/**
	 * Returns the path with the nodes before the index removed; this path only contains the nodes not passed yet
	 * @return
	 */
	public Path getTrimmedPath(boolean includePrevious){
		if(index == 0 && includePrevious)
			throw new IllegalArgumentException("Cannot include previous crossroad when index is 0");
		Path res = new Path();
		if(includePrevious)
			res.totalPath.add(totalPath.get(index-1));
		for(int i = index; i < this.totalPath.size() ; i++){
			res.totalPath.add(totalPath.get(i));
		}
		return res;
	}

	//	public Crossroad next(){
	//		if(index >= totalPath.size()-1)
	//			throw new UnsupportedOperationException("Cannot go past the last crossroad");
	//		this.index++;
	//		this.updateDistanceLeft();
	//		return this.totalPath.get(index);
	//
	//	}

	public void increaseIndex(){
		if(index >= totalPath.size()-1)
			throw new UnsupportedOperationException("Cannot go past the last crossroad");
		this.index++;
		this.updateDistanceLeft();

	}

	public Crossroad getNext() {
		return this.totalPath.get(index+1);
	}

	public Crossroad getCrossroadNextTo(Crossroad crossroad){
		for(int i = 0; i < this.totalPath.size(); i++){
			if(this.totalPath.get(i).equals(crossroad))
				return this.totalPath.get(i+1);
		}
		return null;
	}

	public boolean isAtPackage(Truck truck) {
		if(!truck.isOnConnector())
			return false;
		else if(truck.getConnectorPosition().getConnector().hasPackage())
			return true;
		return false;
	}

	public boolean isAtLast(Truck truck) {
		if(!truck.isOnConnector())
			return false;
		else if(truck.getConnectorPosition().getConnector().equals(this.totalPath.get(this.totalPath.size()-1)))
			return true;
		return false;
	}

	public Path getPathStartingFrom(Crossroad cr) {
		int index = this.totalPath.indexOf(cr);
		if( index != -1){
			ArrayList<Crossroad> result = new ArrayList<Crossroad>();
			for(int i = index; i < this.totalPath.size(); i++){
				result.add(this.totalPath.get(i));
			}
			return new Path(result);
		}else{
			return null;
		}
	}

	public boolean contains(Crossroad connector) {
		return this.totalPath.contains(connector);
	}
}
